<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 原型继承继承:
    // 目的:让子类创建的实例化对象 可以访问 父类原型对象上的属性和方法

    // 缺点: 只能继承父类原型对象上的属性和方法 => 不能继承父类构造函数中实例的相关属性和方法





    // 为什么子类创建的实例化对象 不能访问 父类原型对象上的属性和方法
    // p的原型链
    // p -> Person.prototype -> Object.prototype ->null

    // yp原型链
    // yp ->  YellowPerson.prototype -> Object.prototype ->null

    // 所以:  子类创建的实例化对象 不能访问 父类原型对象上的属性和方法

    // 怎么解决: 
    // (1) 最low的,也是最简单的原型继承

    function Person(name, age) {
        // this -> 构造函数Person在执行过程中创建的实例化对象
        this.name = name;
        this.age = age;
    }

    Person.prototype.species = "human";
    Person.prototype.skill = function () {
        console.log("thinking");
    }
    Person.prototype.say = function () {
        console.log(this.name, this.age);
    }

    var p = new Person("张三", 18);
    console.log(p);


    function YellowPerson(name, age, hobby) {
        // this -> 构造函数YellowPerson在执行过程中创建的实例化对象
        this.hobby = hobby;
    }

    // p和yp 的原型链
    // p -> Person.prototype -> Object.prototype ->null
    // yp ->  YellowPerson.prototype(Person.prototype) -> Object.prototype ->null

    // (1) 最low的, 也是最简单的原型继承  => 缺点: 对象的复制 -> 浅复制 ->  YellowPerson.prototype和Person.prototype引用同一片内存空间 -> 给YellowPerson.prototype添加属性和方法 -> 会影响Person.prototype

    // 虽然方法low -> 但是提供了思路 -> 在子类的原型链上添加父类的原型对象


    // (2) 用父类的实力化对象覆盖子类的原型对象  => 原型继承 
    // 缺点: 有多余属性name和age
    // YellowPerson.prototype = new Person("张三", 18);
    // new Person("张三", 18) => {
    //     name:"张三",
    //     age:18,
    //     [[Prototype]]:Person.prototype
    // }

    // YellowPerson.prototype = {
    //     name:"张三",
    //     age:18,
    //     [[Prototype]]:Person.prototype
    // }

    // 修改后yp的原型链:
    //  yp -> YellowPerson.prototype(父类的实例化对象) -> Person.prototype -> Object.prototype -> null

    // 3. 目的为了得到一个纯净的实例化对象 -> 
    //  {
    //     [[Prototype]]:Person.prototype
    // }

    // a. 自定义一个对象 将原型[[Prototype]]指向 Person.prototype (自己写)
    // var obj = new Object();
    // Object.setPrototypeOf(obj, Person.prototype);
    // console.log(obj);

    // b. 官方的方法 Object.create();
    // var obj = Object.create(Person.prototype);

    // c. 中间件继承(寄生式继承)
    function Fn() { }
    Fn.prototype = Person.prototype;

    var obj = new Fn();  // {[[Prototype]]:Fn.prototype(Person.prototype)}

    // YellowPerson.prototype = { constructor: YellowPerson }
    YellowPerson.prototype = obj;
    YellowPerson.prototype.constructor = YellowPerson; // 以假乱真

    YellowPerson.prototype.speak = function () {
        console.log("chinese");
    }

    // debugger;
    var yp = new YellowPerson("张三", 18, "sing");
    console.log(yp);

    // console.log(yp.species);
    // console.log(yp.skill);
    // console.log(yp.speak);

</script>

</html>